Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Logs] OpenTelemetry.Extensions.EventSource extensions project #3454

Merged

Conversation

CodeBlanch
Copy link
Member

@CodeBlanch CodeBlanch commented Jul 18, 2022

[Goal is to pare down the amount of changes on #3305]

Changes

Notes

  • This project is currently part of the core repo because all of the LogEmitter artifacts are internal. Once those go public this should be moved to contrib repo.
  • The goal here is to release this project as an experimental/preview thing to gather feedback.

TODOs

  • Appropriate CHANGELOG.md updated for non-trivial changes
  • Unit tests

@CodeBlanch CodeBlanch requested a review from a team July 18, 2022 17:34
<PropertyGroup>
<!-- OmniSharp/VS Code requires TargetFrameworks to be in descending order for IntelliSense and analysis. -->
<TargetFrameworks>netstandard2.1;netstandard2.0</TargetFrameworks>
<Description>Extensions for using OpenTelemetry with System.Diagnostics.Tracing</Description>
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know the name OpenTelemetry.Extensions.Tracing is going to be a lightning rod but I'll explain my thinking here.

My intention was this project would contain extensions for things in the System.Diagnostics.Tracing namespace. EventSource but also EventCounters. IMO OpenTelemetry.Instrumentation.EventCounters is misnamed.

Anyway open to alternatives just thought I would explain myself 😄

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My intention was this project would contain extensions for things in the System.Diagnostics.Tracing namespace.

Then we could probably add Diagnostics in the package name: OpenTelemetry.Extensions.Diagnostics.Tracing because just OpenTelemetry.Extensions.Tracing might suggest that these would be extensions for OTel Traces covering things such as AutoFlushActivityProcessor

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚡ ⚡ !! Haha, yea naming is a bummer. We should all just stop using words.

Understood that System.Diagnostics.Tracing namespace involves more than EventSource, but were you envisioning that this package might one day involve itself with EventCounters somehow?

OpenTelemetry.Extensions.EventSource was my favorite of my suggestions here
#3305 (comment). But I could get behind the OpenTelemetry.Extensions.Diagnostics.Tracing or even more precisely including the whole namespace OpenTelemetry.Extensions.System.Diagnostics.Tracing ... even though it gives me a minor headache 🥴.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we have separate packages for OpenTelemetry.Extensions.EventCounter and OpenTelemetry.Extensions.EventSource? (e.g. I guess there are far more developers who need EventSource integration comparing to EventCounter)

I prefer separate packages because they can be deprecated independently.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK I'll rename this OpenTelemetry.Extensions.EventSource and get to work on tests. @utpilla You want me to open issue to rename OpenTelemetry.Instrumentation.EventCounters -> OpenTelemetry.Extensions.EventCounter?

Copy link
Member Author

@CodeBlanch CodeBlanch Jul 21, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[This reply is to @utpilla + @cijothomas I had it open for a while and didn't see @alanwest sneak in there. I'm good with punting on this discussion.]

Hmm interesting. Hard time wrapping my mind around this. Is this definition from the spec somewhere? User plugging this stuff in is doing so at the host level so I'm not sure if the API/SDK distinction is useful.

Just eyeballing this list...

image

Which thing is not like the others? 🍎 🍎 🍎 🍌 🤣

OpenTelemetry.Instrumentation.AspNet - Emits telemetry about AspNet
OpenTelemetry.Instrumentation.MassTransit - Emits telemetry about MassTransit
OpenTelemetry.Instrumentation.Runtime - Emits telemetry about.NET runtime
OpenTelemetry.Instrumentation.StackExchangeRedis - Emits telemetry about Redis
...etc...
OpenTelemetry.Instrumentation.EventCounters - Transposes telemetry written about whatever using EventCounters into System.Diagnostics.DiagnosticSource telemetry. Does not emit telemetry about EventCounters

IMO the HOW it is done is less important than WHAT it is doing.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this definition from the spec somewhere?

No. My view !
Only spec defined term is https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/glossary.md#instrumentation-library

We need to definitely discuss this more.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMO the HOW it is done is less important than WHAT it is doing.

💯

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes 💯 to that as well. I think I've captured the spirit of WHAT in the issue I just opened #3469.

Also, per my thoughts in #3469, I've changed my mind and I think this package should be OpenTelemetry.Shims.EventSource 😆.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Which thing is not like the others? 🍎 🍎 🍎 🍌 🤣

Also, rename OpenTelemetry.Extensions.EventCounter -> OpenTelemetry.🍌

@codecov
Copy link

codecov bot commented Jul 18, 2022

Codecov Report

Merging #3454 (f02ec69) into main (795aedc) will increase coverage by 0.29%.
The diff coverage is 96.20%.

Impacted file tree graph

@@            Coverage Diff             @@
##             main    #3454      +/-   ##
==========================================
+ Coverage   86.10%   86.40%   +0.29%     
==========================================
  Files         269      270       +1     
  Lines        9712     9791      +79     
==========================================
+ Hits         8363     8460      +97     
+ Misses       1349     1331      -18     
Impacted Files Coverage Δ
....EventSource/OpenTelemetryEventSourceLogEmitter.cs 96.20% <96.20%> (ø)
...metryProtocol/Implementation/ActivityExtensions.cs 94.50% <0.00%> (+3.29%) ⬆️
...xporter.OpenTelemetryProtocol/OtlpTraceExporter.cs 77.27% <0.00%> (+40.90%) ⬆️
...entation/ExportClient/OtlpGrpcTraceExportClient.cs 78.57% <0.00%> (+42.85%) ⬆️

@CodeBlanch CodeBlanch changed the title [Logs] System.Diagnostics.Tracing extensions project [Logs] OpenTelemetry.Extensions.EventSource extensions project Jul 21, 2022
// names matching OpenTelemetry* into logs
using var openTelemetryEventSourceLogEmitter = new OpenTelemetryEventSourceLogEmitter(
openTelemetryLoggerProvider, // <- Events will be written to openTelemetryLoggerProvider
(name) => name.StartsWith("OpenTelemetry") ? EventLevel.LogAlways : null,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Was it intentional that "OpenTelemetry" was used? any risk of cyclic/loops?
Might be good to create a custom EventSource-Foo or something, and use that in examples?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ya it was intentional. I just added this comment to explain the behavior:

// Manually dispose OpenTelemetryLoggerProvider since it is being shared. This
// causes a log message to be written to the OpenTelemetry-Sdk EventSource which
// OpenTelemetryEventSourceLogEmitter will capture.

I'm open to changing it LMK what you think about that.

Doesn't have any cyclic or loop issues currently as OpenTelemetry.Extensions.EventSource doesn't have its own EventSource.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see.
I meant this when I said cyclic loop:

If I enable this EventSourceLogEmitter, it'll subscribe to all ES starting with OpenTelemetry, and pipes them to OTel Logging SDK.

OTel Logging SDK internally uses ES whose name starts with OpenTelemetry. So that EventSource Logs gets piped through this LoggingSDK again, which inturn produce more log....

(or did i got it wrong fully 🏃 )

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The enduser for this package is people who already EventSource for their logging, and want those piped through OTel logging. For such use-cases, the best would be to show a custom EventSource, logging to it, but it showing up in OTel logging.
Similar to the example for Serilog...

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Member

@cijothomas cijothomas left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM.
Left a comment about the example - I think it should show a custom EventSource (and not OpenTelemetry event source!)


// Note: It is important that OpenTelemetryLoggerProvider is disposed when the
// app is shutdown. In this example we allow Serilog to do that by calling CloseAndFlush.
var openTelemetryLoggerProvider = new OpenTelemetryLoggerProvider(options =>
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@alanwest @cijothomas @utpilla One thing I realized working on tests. The Serilog + EventSource APIs ask you to pass in the OpenTelemetryLoggerProvider. If you are creating it manually, that is super easy to do. However if you are using the ILoggingBuilder extension it is tricky/non-obvious how you get the actual OpenTelemetryLoggerProvider. Maybe as a follow-up I'll see if we can smooth that out somehow?

Copy link
Member

@alanwest alanwest left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM if you can get it to build 😄.

I really do think we should consider using the term Shims over Extensions but fine to follow up with that rename if folks want to mull it over more.


LogRecordAttributeList attributes = default;

attributes.Add("event_source.name", eventData.EventSource.Name);
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@cijothomas @alanwest @reyang @utpilla Right now EventSource.Name becomes the event_source.name tag. CategoryName is null. Anyone feel like EventSource.Name should end up the CategoryName and we should drop the tag? I kind of feel like that would be a good change.

Copy link
Member

@alanwest alanwest Jul 22, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hmm. Well the goofy thing about CategoryName is that it is an ILogger concept. We've taken the stance to kind of treat ILogger as special in OpenTelemetry libraries. I'm not sure it makes sense to try to coerce other logging libraries concepts into ILogger concepts.

From the standpoint of OTLP we currently transform CategoryName into an attribute named dotnet.ilogger.category.

if (!string.IsNullOrEmpty(logRecord.CategoryName))
{
// TODO:
// 1. Track the following issue, and map CategoryName to Name
// if it makes it to log data model.
// https://github.com/open-telemetry/opentelemetry-specification/issues/2398
// 2. Confirm if this name for attribute is good.
otlpLogRecord.Attributes.AddStringAttribute("dotnet.ilogger.category", logRecord.CategoryName);
}

It might actually make more sense to abandon the use of CategoryName and add an appropriately named attribute to the LogRecord upstream just like you've done here with event_source.name. If some some other extension author ends up using CategoryName somehow, then It think in the context of OTLP we should just map that to an attribute named dotnet.otel.category_name or something.

Copy link
Member

@alanwest alanwest Jul 22, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also regarding the comment

// 1.Track the following issue, and map CategoryName to Name
// if it makes it to log data model.

The Name field did not make it into the data model: open-telemetry/opentelemetry-proto#357, and I think at this point in time we should assume a world where it never comes back. And even if it did, I'm still beginning to think that attributes named in a way that reflect the logging library that was used is more correct.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You convinced me to just leave it alone (as event_source.name tag).

FYI in the Serilog sink I do have this code...

if (property.Key == Constants.SourceContextPropertyName
&& property.Value is ScalarValue sourceContextValue)
{
data.CategoryName = sourceContextValue.Value as string;
}

...which will set CategoryName when users use the ForContext API...

ILogger programLogger = Log.Logger.ForContext<Program>(); // <- CategoryName will be essentially typeof(Program).FullName

Seemed like a good fit to me but we may want to change that?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, didn't see your comment here... yes, we need to consider what to do. Opened #3491 for discussion.

I'm not familiar enough with Serilog to make a suggestion here. Seems like a serilog.context attribute may make sense? Though, a quick search over Serilog code leads me to believe ForContext may be a bit more complex than just a name - look at this for example: https://github.com/serilog/serilog/blob/697a23189e3068bfe0da1460a2676913239d2757/src/Serilog/LoggerExtensions.cs#L24-L29... though maybe this is more akin to ILogger scopes?

@CodeBlanch
Copy link
Member Author

@alanwest

LGTM if you can get it to build 😄.

Fine. It now builds too! What you want from me? 🤣

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants